feat(efcore): Weasel model → EF MigrationOperation translation layer - #375
Merged
Conversation
Closes #365. First implementation phase of the EF Core migration generation epic (#371), building on the #364 spike results. - New MigrationOperationTranslation in Weasel.EntityFrameworkCore: walks the provider-neutral surface (ITable/ITableColumn/ITableIndex/ ForeignKeyBase/SequenceBase) and produces EF Core MigrationOperation instances — the reverse of MapToTable. Raw store type strings (ColumnType) everywhere so EF's CLR mapping is bypassed and DDL matches Weasel exactly; the CLR type is a best-effort inverse used only for the Column<T>() generic in emitted C# - CreateTable with nested columns / primary key / check constraints / foreign keys, one CreateIndex per index, EnsureSchema per non-default schema (deduplicated; default public/dbo emitted as null Schema like EF's own scaffolding), CreateSequence from SequenceBase - Provider specifics: identity → Npgsql:ValueGenerationStrategy or SqlServer:Identity annotations; computed columns → ComputedColumnSql + IsStored (always stored on PG); index includes/method annotations; CascadeAction → ReferentialAction with SQL Server Restrict ≡ NoAction mirroring mapDeleteBehavior - Raw-SQL fallback: non-table/non-sequence objects (functions, sprocs, table types) and anything matched by the ForceRawSql hook (e.g. partitioned tables) are wrapped in SqlOperation carrying the object's own WriteCreateStatement DDL; expression indexes throw with guidance to use the hook - ToDropMigrationOperations for Down() bodies: reverse-order DropTable / DropSequence / raw drops; schemas never dropped (may be shared with Marten/Wolverine) - Weasel.Core additions: ITable.Columns and ITableIndex.Columns expose the column collections on the neutral surface (implicitly satisfied by every provider's concrete types) 13 new DB-free unit tests; all provider suites green locally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Jul 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #365. First implementation phase of the EF Core migration generation epic (#371), building directly on the verified #364 spike results (attribute-only migrations with empty target models are first-class in the EF toolchain).
What's here
New
MigrationOperationTranslationinWeasel.EntityFrameworkCore— the reverse direction ofMapToTable: walk Weasel's schema model and produce EF CoreMigrationOperationinstances, the intermediate representation the C# migration file emitter (#366) will render asMigrationBuildercalls.ITable,ITableColumn,ITableIndex,ForeignKeyBase,SequenceBase) — the project keeps zero concrete-provider references. Two small additive changes toWeasel.Coreexpose what was missing:ITable.ColumnsandITableIndex.Columns(implicitly satisfied by every provider's existing concrete members).ColumnTypeso EF's CLR type mapping is bypassed and the resulting DDL matches Weasel's own exactly. TheClrTypeis a best-effort inverse map used only for thetable.Column<T>(...)generic argument in emitted C#.CreateTablewith nested columns / primary key / check constraints / foreign keys, oneCreateIndexper index,EnsureSchemaper non-default schema (deduplicated;public/dbobecome nullSchema, matching EF's own scaffolding),CreateSequencefromSequenceBase(StartWith/IncrementByfor HiLo).Npgsql:ValueGenerationStrategy/SqlServer:Identityannotations; computed columns →ComputedColumnSql+IsStored(always stored on PostgreSQL); index filter → first-classFilter, includes/method → provider annotations;CascadeAction→ReferentialActionwith SQL ServerRestrict≡NoAction, mirroring themapDeleteBehaviornormalization from the EF→Weasel direction.SqlOperationcarrying the object's ownWriteCreateStatementoutput — non-table/non-sequence schema objects (functions, sprocs, table types) automatically, plus anything matched by theForceRawSqlhook (partitioned tables being the canonical case; callers with provider references downcast there, same pattern as the harness'scustomizeTables). Expression indexes throwNotSupportedExceptionwith guidance to use the hook.ToDropMigrationOperationsbuildsDown()bodies: reverse-orderDropTable/DropSequence/raw drops. Schemas are deliberately never dropped (they may be shared with Marten/Wolverine)."IdentityByDefaultColumn"in-memory (this project can't reference the provider enum); the EF migration generation: C# migration file emitter + stub DbContext #366 emitter renders it as the properNpgsqlValueGenerationStrategyliteral, and callers feeding operations directly to the Npgsql SQL generator can overwriteNpgsqlIdentityAnnotationValuewith the real enum.Renames (
RenameColumnOperation/RenameTableOperation) belong to the incrementalTableDeltaphase (#367) per the issue's design note.Testing
13 new DB-free unit tests covering: full PG table shape (raw types, nullability, defaults, identity annotation, PK, checks), SQL Server identity, computed columns both providers, index filter/includes/method, expression-index rejection, FK referential actions incl. the Restrict normalization split, default-schema omission, sequence translation,
ForceRawSqlpartitioned-table fallback, missing-Migrator error, drop ordering, andPreserveIdentifierCaseflow-through.End-to-end validation (operations → SQL → schema comparison) deliberately belongs to #369. Full local suites green: Core 21, SQLite 361, PostgreSQL 767, SQL Server 302, EF Core (PG+SS) 75.
🤖 Generated with Claude Code